home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / oleo-1_4.lha / oleo-1.4 / utils.c < prev    next >
C/C++ Source or Header  |  1993-05-22  |  21KB  |  1,232 lines

  1. /*    Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.
  2.  
  3. This file is part of Oleo, the GNU Spreadsheet.
  4.  
  5. Oleo is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.
  9.  
  10. Oleo is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with Oleo; see the file COPYING.  If not, write to
  17. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. #include <stdio.h>
  20. #include <errno.h>
  21. #include "sysdef.h"
  22.  
  23.  
  24. /* unistd.h defines _POSIX_VERSION on POSIX.1 systems.  */
  25. #if defined(DIRENT) || defined(_POSIX_VERSION)
  26. #include <dirent.h>
  27. #define NLENGTH(dirent) (strlen((dirent)->d_name))
  28. #else /* not (DIRENT or _POSIX_VERSION) */
  29. #define dirent direct
  30. #define NLENGTH(dirent) ((dirent)->d_namlen)
  31. #ifdef SYSNDIR
  32. #include <sys/ndir.h>
  33. #endif /* SYSNDIR */
  34. #ifdef SYSDIR
  35. #include <sys/dir.h>
  36. #endif /* SYSDIR */
  37. #ifdef NDIR
  38. #include <ndir.h>
  39. #endif /* NDIR */
  40. #endif /* not (DIRENT or _POSIX_VERSION) */
  41.  
  42. #ifdef __STDC__
  43. #undef NULL
  44. #endif
  45.  
  46. #include <ctype.h>
  47. #include "utils.h"
  48.  
  49. #ifndef F_OK
  50. #define F_OK 0
  51. #endif
  52. #ifndef _IOSTRG
  53. #define _IOSTRG 0
  54. #endif
  55.  
  56. #ifdef __STDC__
  57. extern void abort (void);
  58. extern void *malloc (size_t);
  59. extern void *calloc (size_t, size_t);
  60. extern void *realloc (void *, size_t);
  61. #else
  62. extern void abort ();
  63. extern void *malloc ();
  64. extern void *calloc ();
  65. extern void *realloc ();
  66. #endif
  67.  
  68. extern int sys_nerr;
  69. extern char *sys_errlist[];
  70.  
  71. struct id
  72.   {
  73.     int flag;
  74.     FILE *fp;
  75.     char *name;
  76.   };
  77.  
  78. struct id *__id_s;
  79. int __id_n;
  80. int __id_f;
  81.  
  82. int __make_backups;
  83. int __backup_by_copying;
  84.  
  85. /* Stash argv[0] here so panic will know what the program is called */
  86. char *argv_name = 0;
  87.  
  88. /* Blow chunks! */
  89. #ifdef __STDC__
  90. void
  91. panic (const char *s,...)
  92. #else
  93. void
  94. panic (s, va_alist)
  95.      char *s;
  96.      va_dcl
  97. #endif
  98. {
  99.   va_list iggy;
  100.  
  101.   var_start (iggy, s);
  102.   if (argv_name)
  103.     fprintf (stderr, "%s:", argv_name);
  104.   vfprintf (stderr, s, iggy);
  105.   putc ('\n', stderr);
  106.   va_end (iggy);
  107.   exit (2);
  108. }
  109.  
  110. /* Given a file name, come up with a backup file name. . . */
  111. #ifdef __STDC__
  112. char *
  113. backup_file_name (char *file_name)
  114. #else
  115. char *
  116. backup_file_name (file_name)
  117.      char *file_name;
  118. #endif
  119. {
  120.   char *dir_name, *dir_end;
  121.  
  122.   DIR *dir;
  123.   register struct dirent *dp;
  124.   int len;
  125.   int max_fnum;
  126.   int cur_fnum;
  127.  
  128.   char *tmp_ptr;
  129.  
  130.   char *return_value;
  131.  
  132.   dir_end = (char *)rindex (file_name, '/');
  133.   if (dir_end)
  134.     {
  135.       dir_name = file_name;
  136.       file_name = dir_end + 1;
  137.       *dir_end = '\0';
  138.     }
  139.   else
  140.     {
  141.       dir_name = ".";
  142.     }
  143.   len = strlen (file_name);
  144.  
  145.   dir = opendir (dir_name);
  146.   if (dir == 0)
  147.     {
  148.       if (dir_end)
  149.     *dir_end = '/';
  150.       return (char *) 0;
  151.     }
  152.  
  153.   max_fnum = 0;
  154.   while (dp = readdir (dir))
  155.     {
  156.       if (!dp->d_ino
  157.       || NLENGTH (dp) <= len
  158.       || strncmp (dp->d_name, file_name, len)
  159.       || dp->d_name[len] != '.'
  160.       || dp->d_name[len + 1] != '~'
  161.       || dp->d_name[NLENGTH(dp) - 1] != '~')
  162.     continue;
  163.  
  164.       tmp_ptr = &(dp->d_name[len + 2]);
  165.       for (cur_fnum = 0; isdigit (*tmp_ptr); tmp_ptr++)
  166.     cur_fnum = cur_fnum * 10 + *tmp_ptr - '0';
  167.       if (tmp_ptr != &(dp->d_name[NLENGTH(dp) - 1]) || cur_fnum < max_fnum)
  168.     continue;
  169.       max_fnum = cur_fnum;
  170.     }
  171.   closedir (dir);
  172.   max_fnum++;
  173.   return_value = (char *) malloc (strlen (dir_name) + len + 12);
  174.   if (!return_value)
  175.     return (char *) 0;
  176.   sprintf (return_value, "%s/%s.~%d~", dir_name, file_name, max_fnum);
  177.   if (dir_end)
  178.     *dir_end = '/';
  179.   return return_value;
  180. }
  181.  
  182.  
  183. char *
  184. __fp_name (fp)
  185.      FILE *fp;
  186. {
  187.   int n;
  188.  
  189.   for (n = 0; n < __id_n; n++)
  190.     {
  191.       if (__id_s[n].fp == fp)
  192.     return __id_s[n].name;
  193.     }
  194.   return "{Unknown file pointer}";
  195. }
  196.  
  197. void
  198. __set_fp (fp, name, flag)
  199.      FILE *fp;
  200.      const char *name;
  201.      int flag;
  202. {
  203.   if (__id_s == 0)
  204.     {
  205.       __id_s = ck_malloc (20 * sizeof (struct id));
  206.       __id_n = 0;
  207.       __id_f = 20;
  208.     }
  209.   else
  210.     {
  211.       int n;
  212.  
  213.       for (n = 0; n < __id_n; n++)
  214.     if (__id_s[n].fp == fp)
  215.       {
  216.         free (__id_s[n].name);
  217.         __id_s[n] = __id_s[--__id_n];
  218.         __id_f++;
  219.         break;
  220.       }
  221.     }
  222.   if (__id_f == 0)
  223.     {
  224.       __id_f = 20;
  225.       __id_s = ck_realloc (__id_s, (__id_f + __id_n) * sizeof (struct id));
  226.     }
  227.   __id_s[__id_n].flag = flag;
  228.   __id_s[__id_n].name = strdup (name);
  229.   __id_s[__id_n].fp = fp;
  230.   __id_n++;
  231.   __id_f--;
  232. }
  233.  
  234. /* Open a file or a pipe */
  235. FILE *
  236. xopen (name, mode)
  237.      const char *name;
  238.      const char *mode;
  239. {
  240.   int flag = 0;
  241.   FILE *ret;
  242.  
  243.   while (*name == ' ')
  244.     name++;
  245.   if (*name == '!')
  246.     {
  247.       name++;
  248.       ret = popen (name, mode);
  249.       flag = 1;
  250.     }
  251.   else
  252.     ret = fopen (name, mode);
  253.   if (ret == 0)
  254.     return ret;
  255.   __set_fp (ret, name, flag);
  256.   return ret;
  257. }
  258.  
  259. /* Open a file, creating a backup file if needed. . . */
  260. FILE *
  261. fopen_with_backup (name, mode)
  262.      char *name;
  263.      const char *mode;
  264. {
  265.   char *newname;
  266.   struct stat stat_buf;
  267.   int old_file = 0;
  268.  
  269.   old_file = (stat (name, &stat_buf) >= 0);
  270.  
  271.   if (__make_backups && *mode == 'w' && access (name, F_OK) == 0)
  272.     {
  273.       newname = backup_file_name (name);
  274.       if (!newname)
  275.     return (FILE *) 0;
  276.       if (__backup_by_copying)
  277.     {
  278.       FILE *c_in, *c_out;
  279.       int n_read;
  280.       char buf[4096];
  281.       c_in = fopen (name, "r");
  282.       if (!c_in)
  283.         return 0;
  284.       c_out = fopen (newname, "w");
  285.       {
  286.         int fd;
  287.         if (!old_file || (stat (name, &stat_buf) < 0))
  288.           {
  289.         fclose (c_in);
  290.         return 0;
  291.           }
  292.         fd = creat (newname, stat_buf.st_mode);
  293.         if (fd < 0)
  294.           {
  295.         fclose (c_in);
  296.         return 0;
  297.           }
  298.         chmod (newname, stat_buf.st_mode);
  299.         c_out = fdopen (fd, "w");
  300.         if (!c_out)
  301.           {
  302.         fclose (c_in);
  303.         close (fd);
  304.         return 0;
  305.           }
  306.       }
  307.       while ((n_read = fread (buf, 1, sizeof (buf), c_in)) > 0)
  308.         if (fwrite (buf, 1, n_read, c_out) != n_read)
  309.           {
  310.         fclose (c_in);
  311.         fclose (c_out);
  312.         return (FILE *) 0;
  313.           }
  314.       if (fclose (c_in) == EOF || fclose (c_out) == EOF)
  315.         return (FILE *) 0;
  316.     }
  317.       else
  318. #if defined(HAVE_RENAME)
  319.       if (rename (name, newname) < 0)
  320. #else
  321.       if (link (name, newname) || unlink (name))
  322. #endif
  323.     return (FILE *) 0;
  324.       free (newname);
  325.     }
  326.  
  327.   {
  328.     FILE * ret = fopen (name, mode);
  329.     if (ret && old_file)
  330.       chmod (name, stat_buf.st_mode);
  331.     return ret;
  332.   }
  333. }
  334.  
  335. /* Open a file or a pipe, creating a backup file if it's a file */
  336. FILE *
  337. xopen_with_backup (name, mode)
  338.      const char *name;
  339.      const char *mode;
  340. {
  341.   int flag;
  342.   FILE *ret;
  343.  
  344.   while (*name == ' ')
  345.     name++;
  346.   if (*name == '|')
  347.     {
  348.       ret = popen (name + 1, mode);
  349.       flag = 1;
  350.     }
  351.   else
  352.     {
  353.       ret = fopen_with_backup (name, mode);
  354.       flag = 0;
  355.     }
  356.   if (ret == 0)
  357.     return ret;
  358.   __set_fp (ret, name, flag);
  359.   return ret;
  360. }
  361.  
  362. /* Close something opened with xopen. . . */
  363. int
  364. xclose (fp)
  365.      FILE *fp;
  366. {
  367.   int ret;
  368.   int n;
  369.  
  370.   for (n = 0; n < __id_n; n++)
  371.     {
  372.       if (__id_s[n].fp == fp)
  373.     break;
  374.     }
  375.   if (n == __id_n)
  376.     panic ("Unknown file pointer %p given to xclose", fp);
  377.   if (__id_s[n].flag)
  378.     ret = pclose (fp);
  379.   else
  380.     ret = fclose (fp);
  381.   return ret;
  382. }
  383.  
  384. /* Fclose or panic */
  385. void
  386. ck_fclose (stream)
  387.      FILE *stream;
  388. {
  389.   if (fclose (stream) == EOF)
  390.     panic ("Couldn't close %s", __fp_name (stream));
  391. }
  392.  
  393. /* fopen or panic */
  394. void *
  395. ck_malloc (size)
  396.      size_t size;
  397. {
  398.   void *ret;
  399.  
  400.   ret = malloc (size);
  401.   if (ret == (void *) 0)
  402.     panic ("Couldn't allocate %u bytes", size);
  403.   return ret;
  404. }
  405.  
  406.  
  407. #ifdef __STDC__
  408. void
  409. ck_free (void * mem)
  410. #else
  411. void
  412. ck_free (mem)
  413.      void * mem;
  414. #endif
  415. {
  416.   if (mem) free (mem);
  417. }
  418.  
  419. #ifdef __STDC__
  420. char *
  421. ck_savestr (char *str)
  422. #else
  423. char *
  424. ck_savestr (str)
  425.      char *str;
  426. #endif
  427. {
  428.   char *newstr = 0;
  429.   if (str)
  430.     {
  431.       int len = strlen (str) + 1;
  432.       newstr = (char *) ck_malloc (len);
  433.       bcopy (str, newstr, len);
  434.     }
  435.   return newstr;
  436. }
  437.  
  438.  
  439. #ifdef __STDC__
  440. char *
  441. ck_savestrn (char *str, int n)
  442. #else
  443. char *
  444. ck_savestrn (str, n)
  445.      char *str;
  446.      int n;
  447. #endif
  448. {
  449.   char *newstr = 0;
  450.   if (str)
  451.     {
  452.       newstr = (char *) ck_malloc (n + 1);
  453.       if (n)
  454.     bcopy (str, newstr, n);
  455.       newstr[n] = '\0';
  456.     }
  457.   return newstr;
  458. }
  459.  
  460. #ifdef __STDC__
  461. void *
  462. ck_calloc (size_t size)
  463. #else
  464. void *
  465. ck_calloc (size)
  466.      size_t size;
  467. #endif
  468. {
  469.   void *ret;
  470.  
  471.   ret = calloc (size, 1);
  472.   if (ret == (void *) 0)
  473.     panic ("Couldn't allocate %u bytes", size);
  474.   return ret;
  475. }
  476.  
  477. /* Realloc or panic */
  478. #ifdef __STDC__
  479. void *
  480. ck_realloc (void *ptr, size_t size)
  481. #else
  482. void *
  483. ck_realloc (ptr, size)
  484.      void *ptr;
  485.      size_t size;
  486. #endif
  487. {
  488.   void *ret;
  489.  
  490.   if (!ptr)
  491.     ret = malloc (size);
  492.   else
  493.     ret = realloc (ptr, size);
  494.   if (ret == (void *) 0)
  495.     panic ("Couldn't re-allocate %u bytes from %p", size, ptr);
  496.   return ret;
  497. }
  498.  
  499. /* Do a sprintf into an allocated buffer. */
  500. char *
  501. #ifdef __STDC__
  502. mk_sprintf (char *str,...)
  503. {
  504.   va_list iggy;
  505. #ifdef __TURBOC__
  506.   static
  507. #endif
  508.   char tmpbuf[1024 * 8];
  509.   char *ret;
  510.  
  511.   va_start (iggy, str);
  512.   vsprintf (tmpbuf, str, iggy);
  513.   va_end (iggy);
  514.   ret = (char *) ck_malloc (strlen (tmpbuf) + 1);
  515.   strcpy (ret, tmpbuf);
  516.   return ret;
  517. }
  518.  
  519. #else
  520.  
  521. mk_sprintf (str, va_alist)
  522.      char *str;
  523.      va_dcl
  524. {
  525.   va_list iggy;
  526. #ifdef __TURBOC__
  527.   static
  528. #endif
  529.   char tmpbuf[1024 * 8];
  530.   char *ret;
  531.  
  532.   va_start (iggy);
  533.   vsprintf (tmpbuf, str, iggy);
  534.   va_end (iggy);
  535.  
  536.   ret = (char *) ck_malloc (strlen (tmpbuf) + 1);
  537.   strcpy (ret, tmpbuf);
  538.   return ret;
  539. }
  540.  
  541. #endif
  542.  
  543. /* Implement a variable sized LIFO stack of pointers to void */
  544.  
  545. struct stack
  546.   {
  547.     int allocated;
  548.     int used;
  549.     void **buf;
  550.   };
  551.  
  552. #define MIN_STACK 20
  553.  
  554. void *
  555. init_stack ()
  556. {
  557.   struct stack *b;
  558.  
  559.   b = (struct stack *) ck_malloc (sizeof (struct stack));
  560.   b->allocated = MIN_STACK;
  561.   b->used = 0;
  562.   b->buf = (void **) ck_malloc (MIN_STACK * sizeof (void *));
  563.   return (void *) b;
  564. }
  565.  
  566. void
  567. flush_stack (bb)
  568.      void *bb;
  569. {
  570.   struct stack *b;
  571.  
  572.   b = (struct stack *) bb;
  573.   free (b->buf);
  574.   b->buf = 0;
  575.   b->allocated = 0;
  576.   b->used = 0;
  577.   free (b);
  578. }
  579.  
  580. void
  581. push_stack (bb, add)
  582.      void *bb;
  583.      void *add;
  584. {
  585.   struct stack *b;
  586.  
  587.   b = (struct stack *) bb;
  588.   if (b->allocated == b->used)
  589.     {
  590.       b->allocated *= 2;
  591.       b->buf = (void **) ck_realloc (b->buf, b->allocated * sizeof (void *));
  592.     }
  593.   b->buf[(b->used)++] = add;
  594. }
  595.  
  596. void *
  597. pop_stack (bb)
  598.      void *bb;
  599. {
  600.   struct stack *b;
  601.  
  602.   b = (struct stack *) bb;
  603.   if (b->used == 0)
  604.     return (void *) 0;
  605.   return b->buf[--(b->used)];
  606. }
  607.  
  608. int
  609. size_stack (bb)
  610.      void *bb;
  611. {
  612.   struct stack *b;
  613.  
  614.   b = (struct stack *) bb;
  615.   return b->used;
  616. }
  617.  
  618. #ifndef HAVE_STRDUP
  619. char *
  620. strdup (str)
  621.      const char *str;
  622. {
  623.   char *ret;
  624.  
  625.   ret = (char *) ck_malloc (strlen (str) + 2);
  626.   strcpy (ret, str);
  627.   return ret;
  628. }
  629. #endif
  630.  
  631. #ifndef HAVE_STRICMP
  632. /*
  633.  * stricmp - compare string s1 to s2, ignoring case
  634.  */
  635.  
  636. #ifdef __STDC__
  637. int
  638. stricmp (const char * s1, const char * s2)
  639. #else
  640. int
  641. stricmp (s1, s2)
  642.      const char *s1;
  643.      const char *s2;
  644. #endif
  645. {
  646.   register const char *scan1;
  647.   register const char *scan2;
  648.   register char chr1, chr2;
  649.  
  650.   scan1 = s1;
  651.   scan2 = s2;
  652.   do
  653.     {
  654.       chr1 = isupper (*scan1) ? tolower (*scan1) : *scan1;
  655.       chr2 = isupper (*scan2) ? tolower (*scan2) : *scan2;
  656.       scan1++;
  657.       scan2++;
  658.     }
  659.   while (chr1 && chr1 == chr2);
  660.  
  661.   /*
  662.      * The following case analysis is necessary so that characters
  663.      * which look negative collate low against normal characters but
  664.      * high against the end-of-string NUL.
  665.      */
  666.   if (chr1 == '\0' && chr2 == '\0')
  667.     return 0;
  668.   else if (chr1 == '\0')
  669.     return -1;
  670.   else if (chr2 == '\0')
  671.     return 1;
  672.   else
  673.     return chr1 - chr2;
  674. }
  675. #endif
  676.  
  677. #ifndef HAVE_STRINCMP
  678. /* strincmp - compare first N chars of strings S1 and S2 */
  679. #ifdef __STDC__
  680. int
  681. strincmp (const char * s1, const char * s2, size_t n)
  682. #else
  683. int
  684. strincmp (s1, s2, n)
  685.      const char *s1;
  686.      const char *s2;
  687.      size_t n;
  688. #endif
  689. {
  690.   register const char *scan1;
  691.   register const char *scan2;
  692.   register size_t count;
  693.   register char chr1, chr2;
  694.  
  695.   scan1 = s1;
  696.   scan2 = s2;
  697.   count = n;
  698.   do
  699.     {
  700.       chr1 = isupper (*scan1) ? tolower (*scan1) : *scan1;
  701.       chr2 = isupper (*scan2) ? tolower (*scan2) : *scan2;
  702.       scan1++;
  703.       scan2++;
  704.     }
  705.   while (--count != 0 && chr1 && chr1 == chr2);
  706.  
  707.   /* if (count == (size_t)-1)
  708.         return 0; */
  709.  
  710.   /*
  711.      * The following case analysis is necessary so that characters
  712.      * which look negative collate low against normal characters but
  713.      * high against the end-of-string NUL.
  714.      */
  715.   if (chr1 == '\0' && chr2 == '\0')
  716.     return 0;
  717.   else if (chr1 == '\0')
  718.     return -1;
  719.   else if (chr2 == '\0')
  720.     return 1;
  721.   else
  722.     return chr1 - chr2;
  723. }
  724. #endif
  725.  
  726. #ifndef HAVE_STRSTR
  727. #ifdef __STDC__
  728. char *
  729. strstr (const char *s, const char *wanted)
  730. #else
  731. char *
  732. strstr (s, wanted)
  733.      const char *s;
  734.      const char *wanted;
  735. #endif
  736. {
  737.   register const char *scan;
  738.   register size_t len;
  739.   register char firstc;
  740.  
  741.   /*
  742.      * The odd placement of the two tests is so "" is findable.
  743.      * Also, we inline the first char for speed.
  744.      * The ++ on scan has been moved down for optimization.
  745.      */
  746.   firstc = *wanted;
  747.   len = strlen (wanted);
  748.   for (scan = s; *scan != firstc || strncmp (scan, wanted, len) != 0;)
  749.     if (*scan++ == '\0')
  750.       return (char *) 0;
  751.   return scan;
  752. }
  753. #endif
  754.  
  755. #ifdef __STDC__
  756. char *
  757. err_msg (void)
  758. #else
  759. char *
  760. err_msg ()
  761. #endif
  762. {
  763.   int n;
  764.   static char buf[80];
  765.  
  766.   n = errno;
  767.  
  768.   if (n < sys_nerr)
  769.     return sys_errlist[n];
  770.   sprintf (buf, "Unknown error code %d (%#x)", n, n);
  771.   return buf;
  772. }
  773.  
  774.  
  775. /* Take a quoted string and return the character it represents */
  776. #ifdef __STDC__
  777. int
  778. string_to_char (char ** ptr)
  779. #else
  780. int
  781. string_to_char (ptr)
  782.      char **ptr;
  783. #endif
  784. {
  785.   char *str;
  786.   int i;
  787.   char c1, c2;
  788.  
  789.   str = *ptr;
  790.   if (str[0] == '\\')
  791.     {
  792.       switch (str[1])
  793.     {
  794.     case ' ':
  795.       i = ' ';
  796.       break;
  797.     case '\\':
  798.       i = '\\';
  799.       break;
  800.     case 'b':
  801.       i = '\b';
  802.       break;
  803.     case 'f':
  804.       i = '\f';
  805.       break;
  806.     case 'n':
  807.       i = '\n';
  808.       break;
  809.     case 'r':
  810.       i = '\r';
  811.       break;
  812.     case 't':
  813.       i = '\t';
  814.       break;
  815.     case 'x':
  816.       c1 = str[2];
  817.       c2 = str[3];
  818.       if (isxdigit (c1))
  819.         {
  820.           if (isdigit (c1))
  821.         c1 -= '0';
  822.           else if (isupper (c1))
  823.         c1 -= 'A';
  824.           else
  825.         c1 -= 'a';
  826.           if (isxdigit (c2))
  827.         {
  828.           if (isdigit (c2))
  829.             c2 -= '0';
  830.           else if (isupper (c2))
  831.             c2 -= 'A';
  832.           else
  833.             c2 -= 'a';
  834.           i = c1 * 0x10 + c2;
  835.           str++;
  836.         }
  837.           else
  838.         i = c1;
  839.         }
  840.       else
  841.         i = 'x';
  842.       break;
  843.  
  844.     case '0':
  845.     case '1':
  846.     case '2':
  847.     case '3':
  848.     case '4':
  849.     case '5':
  850.     case '6':
  851.     case '7':
  852.       if (str[2] >= '0' && str[2] <= '7')
  853.         {
  854.           if (str[3] >= '0' && str[3] <= '7')
  855.         {
  856.           i = (str[1] - '0') * 0100 + (str[2] - '0') * 010 + (str[3] - '0');
  857.           str += 2;
  858.         }
  859.           else
  860.         {
  861.           i = (str[1] - '0') * 010 + (str[2] - '0');
  862.           str++;
  863.         }
  864.         }
  865.       else
  866.         i = str[1] - '0';
  867.       break;
  868.     default:
  869.       i = str[0];
  870.       --str;
  871.       break;
  872.     }
  873.       str += 2;
  874.       *ptr = str;
  875.       return i;
  876.     }
  877.  
  878.   if (str[0] == 'M' && str[1] == '-')
  879.     {
  880.       i = 0x80;
  881.       str += 2;
  882.     }
  883.   else
  884.     i = 0;
  885.  
  886.   if (str[0] == '^')
  887.     {
  888.       if (str[1] == '\\')
  889.     ++str;
  890.       if (str[1] == '?')
  891.     i += 0x7f;
  892.       else if (str[1] >= '@' && str[1] <= '_')
  893.     i |= str[1] - '@';
  894.       else if (str[1] >= 'a' && str[1] <= 'z')
  895.     i = str[1] - 'a' + 1;
  896.       else if (str[1] == '\0' || isspace (str[1]))
  897.     i = '^';
  898.       else
  899.     return -1;
  900.       str += 2;
  901.     }
  902.   else
  903.     {
  904.       i |= str[0];
  905.       str++;
  906.     }
  907.   *ptr = str;
  908.   return i;
  909. }
  910.  
  911. /* Take a char and turn it into a readable string */
  912. #ifdef __STDC__
  913. char *
  914. char_to_string (int ch)
  915. #else
  916. char *
  917. char_to_string (ch)
  918.      int ch;
  919. #endif
  920. {
  921.   static char buf[] = "M-\0\0\0\0";
  922.  
  923.   if (ch == '\\')
  924.     return "\\\\";
  925.  
  926.   if (ch >= ' ' && ch <= '~')
  927.     {
  928.       buf[3] = ch;
  929.       buf[4] = 0;
  930.       return &buf[3];
  931.     }
  932.  
  933.   if (ch & 0x80)
  934.     {
  935.       ch &= 0x7f;
  936.       if (ch == 0x7f || ch < ' ')
  937.     {
  938.       buf[2] = '^';
  939.       buf[3] = (ch == 0x7f ? '?' : ch + '@');
  940.       if (buf[3] == '\\')
  941.         {
  942.           buf[4] = '\\';
  943.           buf[5] = 0;
  944.         }
  945.       else
  946.         buf[4] = 0;
  947.     }
  948.       else
  949.     {
  950.       buf[2] = ch;
  951.       if (buf[2] == '\\')
  952.         {
  953.           buf[3] = '\\';
  954.           buf[4] = 0;
  955.         }
  956.       else
  957.         buf[3] = '\0';
  958.     }
  959.       return buf;
  960.     }
  961.   if (ch == 0x7f || ch < ' ')
  962.     {
  963.       buf[2] = '^';
  964.       buf[3] = (ch == 0x7f ? '?' : ch + '@');
  965.       if (buf[3] == '\\')
  966.     {
  967.       buf[4] = '\\';
  968.       buf[5] = 0;
  969.     }
  970.       else
  971.     buf[4] = 0;
  972.       return &buf[2];
  973.     }
  974.   return "huh";
  975. }
  976.  
  977.  
  978. #ifdef __STDC__
  979. long
  980. astol (char **ptr)
  981. #else
  982. long
  983. astol (ptr)
  984.      char **ptr;
  985. #endif
  986. {
  987.   register long i = 0;
  988.   register int c;
  989.   int sign = 1;
  990.   char *s;
  991.  
  992.   s = *ptr;
  993.   /* Skip whitespace */
  994.   while (isspace (*s))
  995.     if (*s++ == '\0')
  996.       {
  997.     *ptr = s;
  998.     return (0);
  999.       }
  1000.   /* Check for - or + */
  1001.   if (*s == '-')
  1002.     {
  1003.       s++;
  1004.       sign = -1;
  1005.     }
  1006.   else if (*s == '+')
  1007.     s++;
  1008.  
  1009.   /* Read in the digits */
  1010.   for (; c = *s; s++)
  1011.     {
  1012.       if (!isdigit (c) || i > 214748364 || (i == 214748364 && c > (sign > 0 ? '7' : '8')))
  1013.     break;
  1014.       i = i * 10 + c - '0';
  1015.     }
  1016.   *ptr = s;
  1017.   return i * sign;
  1018. }
  1019.  
  1020. /*
  1021.  *    astof - accept a number of the form:
  1022.  *        (and ignores leading white space)
  1023.  *
  1024.  *    null    ::=
  1025.  *    digit    ::= 0|1|2|3|4|5|6|7|8|9
  1026.  *    digits    ::= <digit>*
  1027.  *    DIGITS    ::= <digit>+
  1028.  *    sign    ::= <null> | + | -
  1029.  *    -------------------------------
  1030.  *        accepted:
  1031.  *    -------------------------------
  1032.  *    integer    ::= <sign><DIGITS>
  1033.  *    real    ::= <integer> . <digits> | <null> . <DIGITS>
  1034.  *    epart    ::= e <integer> | E <integer>
  1035.  *    float    ::= <integer> <epart> | <real> <epart>
  1036.  *
  1037.  *    Always returned as a double
  1038.  *
  1039.  *    There is no particular attempt to reduce mpys/divs
  1040.  *    those machines that are still out there (eg. PDP11/Small)
  1041.  *    that shun floating point arithmetic might rethink this routine.
  1042.  */
  1043.  
  1044. static double exps0[10] =
  1045. {1E0, 1E1, 1E2, 1E3, 1E4, 1E5, 1E6, 1E7, 1E8, 1E9};
  1046. static double exps1[10] =
  1047. {1E00, 1E10, 1E20, 1E30
  1048. #ifndef vax
  1049.  ,1E40, 1E50, 1E60, 1E70, 1E80, 1E90
  1050. #endif
  1051. };
  1052.  
  1053. #define REGISTER register
  1054.  
  1055. #ifdef __STDC__
  1056. double
  1057. astof (char **sp)
  1058. #else
  1059. double
  1060. astof (sp)
  1061.      char **sp;
  1062. #endif
  1063. {
  1064.   REGISTER char *s;
  1065.   REGISTER char *cp;
  1066.   long ipart, epart;
  1067.   int neg = 0;
  1068.   double res;
  1069.   int n;
  1070.  
  1071.   s = *sp;
  1072.   while (isspace (*s))
  1073.     {
  1074.       s++;
  1075.       if (*s == '\0')
  1076.     {
  1077.       *sp = s;
  1078.       return (0.0);
  1079.     }
  1080.     }
  1081.   /*
  1082.      *    Need to handle sign here due to '-.3' or '-0.3'
  1083.      */
  1084.   if (*s == '-')
  1085.     {
  1086.       ++neg;
  1087.       ++s;
  1088.     }
  1089.   else if (*s == '+')
  1090.     ++s;
  1091.   cp = s;
  1092.   /*
  1093.      *    get ipart handling '.n' case
  1094.      */
  1095.   res = 0.0;
  1096.   while (isdigit (*s))
  1097.     {
  1098.       for (n = 0, ipart = 0; n < 6 && isdigit (*s); n++)
  1099.     ipart = ipart * 10 + *s++ - '0';
  1100.       res = res * exps0[n] + (double) ipart;
  1101.     }
  1102.   if (s == cp)
  1103.     {
  1104.       if (*s == '.')
  1105.     ipart = 0;
  1106.       else
  1107.     {
  1108.       *sp = s;
  1109.       return (0.0);
  1110.     }
  1111.     }
  1112.   /*
  1113.      *    either we find a '.' or e|E or done
  1114.      */
  1115.   if (*s == '.')
  1116.     {
  1117.       int m;
  1118.       ++s;
  1119.  
  1120.       m = 0;
  1121.       while (isdigit (*s))
  1122.     {
  1123.       for (n = 0, ipart = 0; n < 6 && isdigit (*s); n++)
  1124.         ipart = ipart * 10 + *s++ - '0';
  1125.       m += n;
  1126.       if (m >= 100)
  1127.         continue;
  1128.       if (m >= 10)
  1129.         res += ((double) ipart) / (exps1[m / 10] * exps0[m % 10]);
  1130.       else
  1131.         res += ((double) ipart) / exps0[m];
  1132.     }
  1133.     }
  1134.   /*
  1135.      *    In either case (.) handle E part
  1136.      */
  1137.   if (*s == 'e' || *s == 'E')
  1138.     {
  1139.       int eneg;
  1140.  
  1141.       ++s;
  1142.       epart = 0;
  1143.       eneg = 0;
  1144.       if (*s == '-')
  1145.     {
  1146.       eneg++;
  1147.       s++;
  1148.     }
  1149.       else if (*s == '+')
  1150.     s++;
  1151.       while (isdigit (*s))
  1152.     epart = epart * 10 + *s++ - '0';
  1153.       if (eneg)
  1154.     {
  1155. #ifndef vax
  1156.       while (epart >= 100)
  1157.         {
  1158.           res /= 1E100;
  1159.           epart -= 100;
  1160.         }
  1161. #endif
  1162.       if (epart > 9)
  1163.         {
  1164.           res /= exps1[epart / 10];
  1165.           epart %= 10;
  1166.         }
  1167.       if (epart)
  1168.         res /= exps0[epart];
  1169.     }
  1170.       else
  1171.     {
  1172. #ifndef vax
  1173.       while (epart >= 100)
  1174.         {
  1175.           res *= 1E100;
  1176.           epart -= 100;
  1177.         }
  1178. #endif
  1179.       if (epart > 9)
  1180.         {
  1181.           res *= exps1[epart / 10];
  1182.           epart %= 10;
  1183.         }
  1184.       if (epart)
  1185.         res *= exps0[epart];
  1186.     }
  1187.     }
  1188.   /*
  1189.      *    fix sign
  1190.      */
  1191.   if (neg)
  1192.     res = -res;
  1193.   *sp = s;
  1194.   return (res);
  1195. }
  1196.  
  1197. #ifdef TEST_ASTOF
  1198. main ()
  1199. {
  1200.   char buf[80];
  1201.   char *ptr;
  1202.   double at, ast;
  1203.   double atof ();
  1204.  
  1205.   while (gets (buf))
  1206.     {
  1207.       at = atof (buf);
  1208.       ptr = buf;
  1209.       ast = astof (&ptr);
  1210.       printf ("%15.6f %15.6f %s ", at, ast, at == ast ? "eq" : "NEQ");
  1211.       if (*ptr)
  1212.     printf ("%s->'%s'\n", buf, ptr);
  1213.       else
  1214.     printf ("%s\n", buf);
  1215.     }
  1216. }
  1217. char *
  1218. ck_savestr (str)
  1219.      char *str;
  1220. {
  1221.   char *newstr = 0;
  1222.   if (str)
  1223.     {
  1224.       int len = strlen (str) + 1;
  1225.       newstr = (char *) ck_malloc (len);
  1226.       bcopy (str, newstr, len);
  1227.     }
  1228.   return newstr;
  1229. }
  1230.  
  1231. #endif
  1232.